<template>
  <div
    :class="animate"
    :style="{ height: height, width: width }"
    :id="chartOption.bindingDiv"
    ref="chartDiv"
  ></div>
</template>

<script>
import echarts from "echarts";
import "echarts-gl";
require("echarts/theme/macarons"); // echarts theme
import resize from "@/views/dashboard/mixins/resize";

import "../../animate/animate.css";

import { parseQueryString, fIsUrL } from "../../util/urlUtil";
import { getFormsource } from "@/api/tool/datav/formsource";
import { chartApiBar, remoteChartApi,chartBIanalysis  } from "@/api/tool/datav/chartApi";
import { linkChart } from "../../util/LinkageChart";
import { addOption } from "../../codegen/codegen";
import VueEvent from "@/views/tool/datav/VueEvent";
//加载json文件
import "echarts/map/js/world";
import "echarts/map/js/china";
import "echarts/map/js/china-contour";
import "echarts/map/js/province/anhui";
import "echarts/map/js/province/aomen";
import "echarts/map/js/province/hebei";
import "echarts/map/js/province/heilongjiang";
import "echarts/map/js/province/henan";
import "echarts/map/js/province/hubei";
import "echarts/map/js/province/hunan";
import "echarts/map/js/province/jiangsu";
import "echarts/map/js/province/jiangxi";
import "echarts/map/js/province/jilin";
import "echarts/map/js/province/liaoning";
import "echarts/map/js/province/neimenggu";
import "echarts/map/js/province/beijing";
import "echarts/map/js/province/ningxia";
import "echarts/map/js/province/qinghai";
import "echarts/map/js/province/shandong";
import "echarts/map/js/province/shanghai";
import "echarts/map/js/province/shanxi";
import "echarts/map/js/province/shanxi1";
import "echarts/map/js/province/sichuan";
import "echarts/map/js/province/taiwan";
import "echarts/map/js/province/tianjin";
import "echarts/map/js/province/xianggang";
import "echarts/map/js/province/chongqing";
import "echarts/map/js/province/xinjiang";
import "echarts/map/js/province/xizang";
import "echarts/map/js/province/yunnan";
import "echarts/map/js/province/zhejiang";
import "echarts/map/js/province/fujian";
import "echarts/map/js/province/gansu";
import "echarts/map/js/province/guangdong";
import "echarts/map/js/province/guangxi";
import "echarts/map/js/province/guizhou";
import "echarts/map/js/province/hainan";

const animationDuration = 6000;
import { websocketCommand } from "../../util/websocket.js";

export default {
  mixins: [resize],
  props: {
    className: {
      type: String,
      default: "chart"
    },
    width: {
      type: String,
      default: "100%"
    },
    height: {
      type: String,
      default: "100%"
    },
    chartOption: {
      type: Object
    },
    drawingList: {
      type: Array
    }
  },
  data() {
    return {
      chart: null,
      //dataOption: this.chartOption,
      timer: "",
      wsObj: null,
      wsFlag: false,
      wsTimer: "",
      wsValue: null,
      animate: this.className
    };
  },
  watch: {
    width() {
      this.$nextTick(() => {
        this.chart.resize();
      });
    },
    height() {
      this.$nextTick(() => {
        this.chart.resize();
      });
    },
    chartOption: {
      deep: true,
      handler(newVal) {
        // 先销毁再重新创建
        this.chart.dispose();
        this.initChart();
        //this.setOptions(JSON.parse(JSON.stringify(newVal)));
      }
    },
    area() {
      // 先销毁再重新创建
      this.chart.dispose();
      this.initChart();
    },
    "chartOption.theme": {
      handler() {
        this.chart.dispose();
        this.chart = null;
        this.initChart();
      }
    },
    "chartOption.timeout": {
      handler() {
        this.chart.dispose();
        this.chart = null;
        this.initChart();
      }
    },
    "chartOption.dataSourceType": {
      handler(value) {
        //切换数据源重新连接
        if (value !== "websocket") {
          this.wsFlag = false;
          //每次切换数据源恢复原来动画
          this.animate = this.className;
        }
        if (value !== "url") {
          clearTimeout(this.timer);
        } 
      }
    },
    "chartOption.interfaceKey": {
      handler(newValue, oldValue) {
        //初始化不创建连接，改变接口地址重新创建
        if (oldValue !== undefined && oldValue != "") {
          this.wsValue = null;
          this.closeWs();
          this.createWs();
          this.animate = this.className;
        }
      }
    },
    wsFlag: {
      handler(value) {
        if (!value) {
          this.wsValue = null;
          this.closeWs();
        }
      }
    },
    className: {
      handler(value) {
        this.animate = value;
      }
    }
  },
  //created 在模板渲染成html前调用，即通常初始化某些属性值，然后再渲染成视图
  created() {
    //循环注册地图
    for (const index in this.areas) {
      echarts.registerMap(index, this.areas[index]);
    }
  },
  //mounted 在模板渲染成html后调用，通常是初始化页面完成后，再对html的dom节点进行一些需要的操作。
  mounted() {
    //this.$nextTick(() => {
    this.initChart();
    //});
  },
  beforeDestroy() {
    //实例销毁之前调用
    if (!this.chart) {
      return;
    }
    //先清空，再重新初始化
    this.chart.dispose();
    this.chart = null;
    clearTimeout(this.timer);
    if (this.wsFlag) {
      this.closeWs();
    }
  },
  methods: {
    initChart() {
      echarts.registerTheme("customTheme", this.chartOption.theme);
      this.chart = echarts.init(this.$el, "customTheme");
      
      //判断是否开启定时器，当是访问url接口时候并且timeout不为0时候开启定时器
      if (this.timer != "") {
        clearTimeout(this.timer);
      }
      if (
        (this.chartOption.dataSourceType == 'url' || this.chartOption.dataSourceType == 'database') &&
        this.chartOption.timeout > 0
      ) {
        let timerTask = () => {
          this.setOptions(JSON.parse(JSON.stringify(this.chartOption)));
          this.timer = setTimeout(() => {
            timerTask();
          }, this.chartOption.timeout);
        };

        timerTask();
      }else{
        this.setOptions(JSON.parse(JSON.stringify(this.chartOption)));
      }
    },
    setOptions: async function(dataOption) {
      //初始化数据
      //如果不是静态数据就调用接口给staticDataValue赋值
      if (dataOption.dataSourceType == "url") {
        let paramJson = parseQueryString(dataOption.requestParameters);

        let interfaceURL = dataOption.interfaceURL;
        dataOption.staticDataValue = await chartApiBar(
          dataOption.requestMethod,
          interfaceURL,
          paramJson,
          dataOption.token
        );
        //console.log(paramJson);
      } else if (dataOption.dataSourceType == "database") {
         if (dataOption.database.executeSql != undefined && dataOption.database.executeSql != '') {
          
          let result = [];
          if(dataOption.database.sqlType == 'custom'){
          
            result = await chartBIanalysis(dataOption.database);
          }
          if (result.code == 200) {
            dataOption.staticDataValue = result.data;
            //console.log(dataOption.staticDataValue);
          } else {
            alert("操作数据库错误");
          }
        }       
      } else if (dataOption.dataSourceType == "form") {
        if (dataOption.formSource != undefined) {
          let response = await getFormsource(dataOption.formSource.id);
          dataOption.staticDataValue = JSON.parse(response.data.formData);
        }
      } else if (dataOption.dataSourceType == "websocket") {
        if (
          dataOption.interfaceKey != undefined &&
          dataOption.interfaceKey != ""
        ) {
          if (!this.wsFlag) {
            this.wsFlag = true;
            this.wsValue = null;
            this.createWs();
          }
          if (this.wsValue != null) {
            dataOption.staticDataValue = this.wsValue;
          }
        }
      }

      // this.area = dataOption.mapName;
      // let geoJson = this.areas[dataOption.mapName];

      // const data = geoJson.features.map((item, index) => {
      //   const geoAreaName = item.properties.name; // geo文件中的地理名称
      //   return {
      //     name: geoAreaName,

      //     coord: item.properties.centroid,
      //     selected: true
      //     // x: 150,
      //     // y: 150
      //   };
      // });

      let mapName = dataOption.mapName;
      let geoCoordMap = {};
      let mapFeatures = echarts.getMap(mapName).geoJson.features;
      mapFeatures.forEach(function(v) {
        // 地区名称
        let name = v.properties.name;
        // 地区经纬度
        geoCoordMap[name] = v.properties.cp;
      });

     
      let convertData = function(data) {
        let res = [];
        for (let i = 0; i < data.length; i++) {
          let geoCoord = geoCoordMap[data[i].name];
          if (geoCoord) {
            res.push({
              name: data[i].name,
              value: typeof data[i].value == 'number'?data[i].value :0
            });
          }
        }
        //console.log(res)
        return res;
      };

      let suffix = dataOption.suffix == undefined?"":dataOption.suffix;

      //计算静态数据最大值
      let max = 100;

      if(typeof dataOption.staticDataValue[0].value== 'number'){

        max = dataOption.staticDataValue.sort((a, b) => {
                return b.value - a.value;
              })[0].value
      }


      // 注册地图名字(tongren)和数据(geoJson)
      var option = {
        bindingType: "threedMap",
        // title: { // 标题
        //   top: '2%',
        //   text: this.area,
        //   subtext: '',
        //   x: 'center',
        //   textStyle: {
        //     color: '#ccc'
        //   }
        // },
        selectedMode: "multiple", // 选中效果固话
        tooltip: {
          // 提示框
          show: true,
          trigger: "item",
          formatter: function(params) {
            return params.name;
          }
        },
        series: [
          {
            name: "map3D",
            type: "map3D", // map3D / map
            map: mapName,
            label: {
              // 标签的相关设置
              show: true, // (地图上的城市名称)是否显示标签 [ default: false ]
              // distance: 5, // 标签距离图形的距离，在三维的散点图中这个距离是屏幕空间的像素值，其它图中这个距离是相对的三维距离
              //formatter:, // 标签内容格式器
              textStyle: dataOption.textStyle,
              // { // 标签的字体样式
              //   color: '#ffffff', // 地图初始化区域字体颜色
              //   fontSize: 14, // 字体大小
              //   opacity: 1, // 字体透明度
              //   backgroundColor: 'rgba(0,23,11,0.5)' // 字体背景色
              // },
              // normal:{
              //   show:true,
              //   formatter:function(params){ //标签内容
              //     // console.log(params)
              //     return  params.name;
              //   },
              //   // lineHeight: 20,
              //   backgroundColor:'rgba(255,255,255,.9)',
              //   borderColor:'#80cffd',
              //   borderWidth:'1',
              //   padding:[5,15,4],
              //   color:'#000000',
              //   fontSize: 12,
              //   fontWeight:'normal',
              // },
              emphasis: {
                show: true,
              }
            },
            tooltip: {
              //提示框组件。
              alwaysShowContent: true,
              hoverAnimation: true,
              trigger: "item", //触发类型 散点图
              enterable: true, //鼠标是否可进入提示框
              transitionDuration: 1, //提示框移动动画过渡时间
              triggerOn: "click",
              //extraCssText: 'white-space: normal; word-break: break-all;',
              formatter: function(params) {
                // console.log(params.name, 'params.name')
                const tooltip = dataOption.staticDataValue.filter(function(
                  item
                ) {
                  return item.name == params.name;
                });
                if (tooltip[0]) {
                  var str = "";
                  if(typeof tooltip[0].value == 'number'){
                    str = `
                    <div class="map-tooltip">
                      <div class="city-name">${tooltip[0].name}：`+tooltip[0].value+suffix+`</div>`;
                  }else{
                    str = `
                    <div class="map-tooltip">
                      <div class="city-name">${tooltip[0].name}</div>`;
                    tooltip[0].value.forEach(element => {
                      str += `<div class="city-info">${element}</div>`;
                    });
                    str = str + `</div>`;
                  }

                  return str;
                }
              },
              backgroundColor: dataOption.tooltip.backgroundColor,
              borderWidth: dataOption.tooltip.borderWidth,
              borderRadius: dataOption.tooltip.borderRadius,
              borderColor: dataOption.tooltip.borderColor,
              textStyle: {
                color: dataOption.tooltip.textStyle.color
              },
              padding: [5, 10]
            },
            itemStyle: dataOption.itemStyle,
            // { // 三维地理坐标系组件 中三维图形的视觉属性，包括颜色，透明度，描边等。
            //   // areaColor: 'rgba(95,158,160,0.5)', // 地图板块的颜色
            //   areaColor: '#10786c', // 地图板块的颜色
            //   opacity: 0.3, // 图形的不透明度 [ default: 1 ]
            //   borderWidth: 2, // (地图板块间的分隔线)图形描边的宽度。加上描边后可以更清晰的区分每个区域 [ default: 0 ]
            //   borderColor: '#5CFFE0' // 图形描边的颜色。[ default: #333 ]
            // },
            viewControl: {
              rotateSensitivity: dataOption.isRotate ? 1 : 0, //旋转灵敏度，0不能旋转
              autoRotate: false,
              animation: false,
              alpha: dataOption.alpha == undefined ? 60 : dataOption.alpha, //上下旋转角度
              beta: dataOption.beta == undefined ? 0 : dataOption.beta, //左右旋转角度
              animationDurationUpdate: 10
            },
            data: convertData(dataOption.staticDataValue),
            // 3d地图添加 markPoint 位置不对
            /*markPoint:{
            symbolSize: 45,
            symbol: 'path://m 0,0 h 48 v 20 h -30 l -6,10 l -6,-10 h -6 z',
            itemStyle: {
              normal: {
                borderColor: '#33CBFF',
                color:'#33CBFF',
                borderWidth: 1,            // 标注边线线宽，单位px，默认为1
                label: {
                  show: true
                }
              }
            },
            data: data
          }*/
          }
        ],
        // staticDataValue: dataOption.staticDataValue
      };


      if(dataOption.visualShow == true){
        option.visualMap = {
            show: true,
            left:dataOption.visualX,
            bottom:dataOption.visualY,
            itemWidth:dataOption.itemWidth,
            itemHeight:dataOption.itemHeight,
            min: 0,
            max: max,
            calculable: true,
            realtime: false,
            inRange: {
                color: dataOption.colors != undefined ?dataOption.colors :['#2884db', '#244779']
            },
            textStyle:{
                color:'#fff',
                fontSize:dataOption.visualFontSize
            }
        }
      }

      //执行通用处理函数
      if(dataOption.customData != undefined && dataOption.customData != ""){
        try {
          option = (
          
            //里面为要处理的代码块
          eval(dataOption.customData) 
          
          )(
            option,
            dataOption.staticDataValue,
            this.$refs.chartDiv
          );
        } catch (error) {
          console.log(error)
        }
       } 
        //交互组件配置
      if(dataOption.interactData != undefined && dataOption.interactData != ""){
          try {
              option = (        
              //里面为要处理的代码块
              eval(dataOption.interactData)             
            )(
            option,
            dataOption.staticDataValue,
            this.$refs.chartDiv
            );
          } catch (error) {
            console.log(error)
          }               
       }
      this.chart.setOption(option, true);
      addOption(dataOption.bindingDiv, option);
      //单击切换到省级地图，当mapCode有值,说明可以切换到下级地图
      // let timeFn = null;
      // this.chart.on("click", (params)=> {
      //   clearTimeout(timeFn);
      //   timeFn = setTimeout(() => {
      //     let mapCode = this.areas[params.name]
      //      this.area = params.name; //地区name
      //      option.series[0].map = params.name;
      //      option.series[0].data = this.getGeoJson(params.name);
      //this.chart.setOption(option, true);

      //   },250);

      // });
      if (dataOption.isLink == true) {
        this.chart.off("click");
        this.chart.on("click", params => {
          //设置参数
          let arrObject = {
            seriesName: params.name,
            data: params.value
          };
          let arrs = JSON.stringify(arrObject);

          //获取绑定的图表
          let bindList = this.chartOption.bindList;

          if (bindList.length > 0) {
            linkChart(dataOption.arrName, arrs, bindList, this.drawingList);
          }
        });
      }
      //开启图表下钻
      else if (dataOption.isDrillDown == true) {
        this.chart.off("click");
        this.chart.on("click", params => {
          //设置参数
          let arrObject = {
            seriesName: params.name,
            data: params.value
          };

          let arrs = JSON.stringify(arrObject);

          //获取绑定的图表
          let drillDownChartOption = this.chartOption.drillDownChartOption;

          if (
            drillDownChartOption != undefined &&
            drillDownChartOption != null
          ) {
            this.$set(
              this.chartOption.drillDownChartOption.chartOption,
              "requestParameters",
              "drillParam=" + arrs
            );
            //发送下钻消息
            VueEvent.$emit(
              "drill_down_msg",
              this.chartOption.drillDownChartOption
            );
          }
        });
      } else {
        //关闭图表联动，取消echart点击事件
        this.chart.off("click");
      }
      //开启远程图表控制
      if (dataOption.isRemote == true) {
        if (dataOption.remote != undefined && dataOption.remote != null) {
          this.chart.off("click");
          this.chart.on("click", params => {
            //设置参数
            let arrObject = {
              seriesName: params.name,
              data: params.value
            };

            let remoteData = { ...dataOption.remote };
            remoteData.query = arrObject;
            //调用接口
            remoteChartApi(remoteData);
          });
        }
      }
    },
    getGeoJson(mapName) {
      let geoJson = this.areas[mapName];

      const data = geoJson.features.map((item, index) => {
        const geoAreaName = item.properties.name; // geo文件中的地理名称

        return {
          name: geoAreaName,

          coord: item.properties.centroid,
          selected: true
          // x: 150,
          // y: 150
        };
      });

      return data;
    },
    //  ws连接成功，后台返回的ws数据
    receiveMsg(e) {
      if (e.action == "chat") {
        // console.log('服务端推送',e);
        this.wsValue = JSON.parse(e.result);
        this.setOptions(JSON.parse(JSON.stringify(this.chartOption)));
      }
    },
    // 建立连接、发起ws请求，以心跳方式，向服务端发送数据
    createWs() {
      this.wsObj = new WebSocket(process.env.VUE_APP_WEBSOCKET);
      // 若为对象类型，以回调方式发送
      websocketCommand(
        this.wsObj,
        "create",
        5000,
        this.chartOption.interfaceKey,
        this.sendHeartBeat,
        this.receiveMsg,
        this.reconnectWs,
        this.wsWarning
      );
    },
    // 断网重连，需要处理的逻辑
    reconnectWs() {
      if (this.wsObj) {
        console.log("%c websocket_reconnect", "color:blue");
        this.createWs();
      }
    },
    // 以回调方式向服务端发送(对象类型的)心跳
    sendHeartBeat() {
      if (this.wsTimer != "") {
        clearTimeout(this.wsTimer);
      }

      let wsTimerTask = () => {
        console.log("发送心跳", "ping");
        let obj = { action: "keep", key: this.chartOption.interfaceKey };
        this.wsObj.send(JSON.stringify(obj));
        this.wsTimer = setTimeout(() => {
          wsTimerTask();
        }, parseInt(process.env.VUE_APP_WEBSOCKET_TIMEOUT));
        this.wsWarning();
      };

      wsTimerTask();
    },
    wsWarning() {
      //如果断开连接则显示组件警告动画并清除计数器
      if (this.wsObj.readyState == 3) {
        this.animate = "warning";
        clearTimeout(this.wsTimer);
      }
    },
    closeWs() {
      clearTimeout(this.wsTimer);
      websocketCommand(
        this.wsObj,
        "close",
        5000,
        this.chartOption.interfaceKey,
        this.sendHeartBeat,
        this.receiveMsg,
        this.reconnectWs,
        this.wsWarning
      );
      this.wsObj = null;
    }
  }
};
</script>
